home *** CD-ROM | disk | FTP | other *** search
- PAGE ,132
- TITLE VDISK - Virtual Disk Device Driver, Version 1.0
-
- ;VDISK simulates a disk drive, using Random Access Memory as the storage medium.
-
- ;(C) Copyright IBM Corporation, 1984
- ;Licensed Material - Program Property of IBM
- ;Author: Dick Dievendorff
-
- ;Add the following statement to CONFIG.SYS
- ; DEVICE=[d:][path]VDISK.SYS bbb sss ddd [/E]
-
- ; where: bbb is the desired buffer size (in kilobytes)
- ; minimum 1KB, maximum is size of available memory,
- ; default is 64KB.
-
- ; VDISK will leave at least 64KB of available memory,
- ; although subsequent device drivers (other than VDISK)
- ; other programs that make themselves resident, and
- ; COMMAND.COM will result in less than 64KB as shown
- ; by CHKDSK.
-
- ; Must be large enough for 1 boot sector + FAT sectors
- ; + 1 directory sector + at least 1 data cluster,
- ; or the device driver won't be installed.
-
- ; sss is the desired sector size (in bytes)
- ; 128, 256, or 512, default is 128.
- ; Will be adjusted if number of FAT entries > 0FE0H
-
- ; ddd is the desired number of directory entries
- ; Minimum 2, maximum 512, default 64.
- ; Will be rounded upward to sector size boundary.
-
- ; /E may only be used if extended memory above 1 megabyte
- ; is to be used. INT 15H functions 87H and 88H are used
- ; to read and write this extended memory.
-
- ; Brackets indicate optional operands.
-
- ; Samples:
- ; DEVICE=\path\VDISK.SYS 160 512 64
- ; results in a 160KB VDISK, with 512 byte sectors, 64 directory entries
-
- ; DEVICE=VDISK.SYS Buffersize 60 Sectorsize 128 Directory entries 32
- ; (since only numbers are interpreted, you may comment the line with
- ; non-numeric characters)
-
- ;Message text for VDISK is in module VDISKMSG.
-
- SUBTTL Structure Definitions
- PAGE
- ;-----------------------------------------------------------------------;
- ; Request Header (Common portion) ;
- ;-----------------------------------------------------------------------;
- RH EQU DS:[BX] ;addressability to Request Header structure
-
- RHC STRUC ;fields common to all request types
- DB ? ;length of Request Header (including data)
- DB ? ;unit code (subunit)
- RHC_CMD DB ? ;command code
- RHC_STA DW ? ;status
- DQ ? ;reserved for DOS
- RHC ENDS ;end of common portion
-
- CMD_INPUT EQU 4 ;RHC_CMD is INPUT request
-
- ;status values for RHC_STA
-
- STAT_DONE EQU 01H ;function complete status (high order byte)
- STAT_CMDERR EQU 8003H ;invalid command code error
- STAT_CRC EQU 8004H ;CRC error
- STAT_SNF EQU 8008H ;sector not found error
- STAT_BUSY EQU 0200H ;busy bit (9) for Removable Media call
- ;-----------------------------------------------------------------------;
- ; Request Header for INIT command ;
- ;-----------------------------------------------------------------------;
- RH0 STRUC
- DB (TYPE RHC) DUP (?) ;common portion
- RH0_NUN DB ? ;number of units
- ;set to 1 if installation succeeds,
- ;set to 0 to cause installation failure
- RH0_ENDO DW ? ;offset of ending address
- RH0_ENDS DW ? ;segment of ending address
- RH0_BPBO DW ? ;offset of BPB array address
- RH0_BPBS DW ? ;segment of BPB array address
- RH0_DRIV DB ? ;drive code (DOS 3 only)
- RH0 ENDS
-
- RH0_BPBA EQU DWORD PTR RH0_BPBO ;offset/segment of BPB array address
- ;Note: RH0_BPBA at entry to INIT points to all after DEVICE= on CONFIG.SYS stmt
-
- ;-----------------------------------------------------------------------;
- ; Request Header for MEDIA CHECK Command ;
- ;-----------------------------------------------------------------------;
- RH1 STRUC
- DB (TYPE RHC) DUP (?) ;common portion
- DB ? ;media descriptor
- RH1_RET DB ? ;return information
- RH1 ENDS
- ;-----------------------------------------------------------------------;
- ; Request Header for BUILD BPB Command ;
- ;-----------------------------------------------------------------------;
- RH2 STRUC
- DB (TYPE RHC) DUP(?) ;common portion
- DB ? ;media descriptor
- DW ? ;offset of transfer address
- DW ? ;segment of transfer address
- RH2_BPBO DW ? ;offset of BPB table address
- RH2_BPBS DW ? ;segment of BPB table address
- RH2 ENDS
- ;-----------------------------------------------------------------------;
- ; Request Header for INPUT, OUTPUT, and OUTPUT with verify ;
- ;-----------------------------------------------------------------------;
- RH4 STRUC
- DB (TYPE RHC) DUP (?) ;common portion
- DB ? ;media descriptor
- RH4_DTAO DW ? ;offset of transfer address
- RH4_DTAS DW ? ;segment of transfer address
- RH4_CNT DW ? ;sector count
- RH4_SSN DW ? ;starting sector number
- RH4 ENDS
-
- RH4_DTAA EQU DWORD PTR RH4_DTAO ;offset/segment of transfer address
-
- ;-----------------------------------------------------------------------;
- ; Segment Descriptor (part of Global Descriptor Table) ;
- ;-----------------------------------------------------------------------;
- DESC STRUC ;data segment descriptor
- DESC_LMT DW 0 ;segment limit (length)
- DESC_BASEL DW 0 ;bits 15-0 of physical address
- DESC_BASEH DB 0 ;bits 23-16 of physical address
- DB 0 ;access rights byte
- DW 0 ;reserved
- DESC ENDS
-
- SUBTTL Equates and Macro Definitions
- PAGE
-
- MEM_SIZE EQU 12H ;BIOS memory size determination INT
- ;returns system size in KB in AX
-
- EM_INT EQU 15H ;extended memory BIOS interrupt INT
- EM_BLKMOVE EQU 87H ;block move function
- EM_MEMSIZE EQU 88H ;memory size determination in KB
-
- BOOT_INT EQU 19H ;bootstrap DOS
-
- DOS EQU 21H ;DOS request INT
- DOS_PCHR EQU 02H ;print character function
- DOS_PSTR EQU 09H ;print string function
- DOS_VERS EQU 30H ;get DOS version
-
- TAB EQU 09H ;ASCII tab
- LF EQU 0AH ;ASCII line feed
- CR EQU 0DH ;ASCII carriage return
-
- PARA_SIZE EQU 16 ;number of bytes in one 8088 paragraph
- DIR_ENTRY_SIZE EQU 32 ;number of bytes per directory entry
- MAX_FATE EQU 0FE0H ;largest number of FAT entries allowed
-
- ;default values used if parameters are omitted
-
- DFLT_BSIZE EQU 64 ;default VDISK buffer size (KB)
- DFLT_SSZ EQU 128 ;default sector size
- DFLT_DIRN EQU 64 ;default number of directory entries
-
- MIN_DIRN EQU 2 ;minimum number of directory entries
- MAX_DIRN EQU 512 ;maximum number of directory entries
-
- STACK_SIZE EQU 512 ;length of stack during initialization
-
- ;-----------------------------------------------------------------------;
- ; MSG invokes the console message subroutine ;
- ;-----------------------------------------------------------------------;
-
- MSG MACRO TEXT
- PUSH DX ;;save DX across call
- MOV DX,OFFSET TEXT ;;point to message
- CALL SHOW_MSG ;;issue message
- POP DX
- ENDM
-
-
- SUBTTL Resident Data Area
- PAGE
- ;-----------------------------------------------------------------------;
- ; Map INT 19H vector in low storage ;
- ;-----------------------------------------------------------------------;
- INT_VEC SEGMENT AT 00H
- ORG 4*BOOT_INT
- BOOT_VEC LABEL DWORD
- BOOT_VECO DW ? ;offset
- BOOT_VECS DW ? ;segment
- INT_VEC ENDS
-
-
- CSEG SEGMENT PARA PUBLIC 'CODE'
- ASSUME CS:CSEG
- ;-----------------------------------------------------------------------;
- ; Resident data area. ;
- ; ;
- ; All variables and constants required after initialization ;
- ; part one are defined here. ;
- ;-----------------------------------------------------------------------;
-
- START EQU $ ;begin resident VDISK data & code
-
- ;DEVICE HEADER - must be at offset zero within device driver
- DD -1 ;becomes pointer to next device header
- DW 0800H ;attribute (IBM format block device)
- ;supports OPEN/CLOSE/RM calls
- DW OFFSET STRATEGY ;pointer to device "strategy" routine
- DW OFFSET IRPT ;pointer to device "interrupt handler"
- DB 1 ;number of block devices
- DB 7 DUP (?) ;7 byte filler (remainder of 8-byte name)
-
- ;END OF DEVICE HEADER
-
- ;This volume label is placed into the directory of the new VDISK
- ;This constant is also used to determine if a previous extended memory VDISK
- ;has been installed.
-
- VOL_LABEL DB 'VDISK V1.0' ;00-10 volume name (shows program level)
-
- DB 08H ;11-11 attribute (volume label)
- DT 0 ;12-21 reserved
-
- DW 6000H ;22-23 time=12:00 noon
- DW 08E3H ;24-25 date=07/03/84
- VOL_LABEL_LEN EQU $-VOL_LABEL ;length of volume label
-
- ;The following field, in the first extended memory VDISK device driver,
- ;is the 24-bit address of the first free byte of extended memory.
- ;This address is not in the common offset/segment format.
- ;The initial value, 10 0000H, is 1 megabyte.
-
- AVAIL_LO DW 0 ;address of first free byte of
- AVAIL_HI DB 10H ;extended memory
-
- ;The INT 19H vector is "stolen" by the first VDISK installed in extended memory.
- ;The original content of the interrupt vector is saved here.
-
- INTV19 LABEL DWORD
- INTV19O DW ? ;offset
- INTV19S DW ? ;segment
-
- PARAS_PER_SECTOR DW ? ;number of 16-byte paragraphs in one sector
-
- START_BUFFER_PARA DW ? ;segment address of start of VDISK buffer
- ;for extended memory, this segment address
- ;is the end of the VDISK device driver.
-
- EM_SW DB 0 ;non-zero if Extended Memory
-
- EM_STAT DW 0 ;AX from last unsuccessful extended memory I/O
-
- START_EM_LO DW ? ;24-bit address of start of VDISK buffer
- START_EM_HI DB ? ;(extended memory only)
-
- WPARA_SIZE DW PARA_SIZE ;number of bytes in one paragraph
-
- MAX_CNT DW ? ;(0FFFFH/BPB_SSZ) truncated, the maximum
- ;number of sectors that can be transferred
- ;without worrying about 64KB wrap
-
- SECT_LEFT DW ? ;sectors left to transfer
-
- IO_SRCA LABEL DWORD ;offset/segment of source
- IO_SRCO DW ? ;offset
- IO_SRCS DW ? ;segment
-
- IO_TGTA LABEL DWORD ;offset/segment of target
- IO_TGTO DW ? ;offset
- IO_TGTS DW ? ;segment
-
- ;-----------------------------------------------------------------------;
- ; BIOS Parameter Block (BPB) ;
- ;-----------------------------------------------------------------------;
- ;This is where the characteristics of the virtual disk are established.
- ;A copy of this block is moved into the boot record of the virtual disk.
- ;DEBUG can be used to read sector zero of the virtual disk to examine the
- ;boot record copy of this block.
-
- BPB LABEL BYTE ;BIOS Parameter Block (BPB)
- BPB_SSZ DW 0 ;number of bytes per disk sector
- BPB_AUSZ DB 1 ;sectors per allocation unit
- BPB_RES DW 1 ;number of reserved sectors (for boot record)
- BPB_FATN DB 1 ;number of File Allocation Table (FAT) copies
- BPB_DIRN DW 0 ;number of root directory entries
- BPB_SECN DW 1 ;total number of sectors
- ;computed from buffer size and sector size
- ;(this includes reserved, FAT, directory,
- ;and data sectors)
- BPB_MCB DB 0FEH ;media descriptor byte
- BPB_FATSZ DW 1 ;number of sectors occupied by a single FAT
- ;computed from BPBSSZ and BPBSECN
- BPB_LEN EQU $-BPB ;length of BIOS parameter block
-
- BPB_PTR DW BPB ;BIOS Parameter Block pointer array (1 entry)
- ;-----------------------------------------------------------------------;
- ; Request Header (RH) address, saved here by "strategy" routine ;
- ;-----------------------------------------------------------------------;
- RH_PTRA LABEL DWORD
- RH_PTRO DW ? ;offset
- RH_PTRS DW ? ;segment
- ;-----------------------------------------------------------------------;
- ; Global Descriptor Table (GDT), used for extended memory moves ;
- ;-----------------------------------------------------------------------;
- ;Access Rights Byte (93H) is
- ; P=1 (segment is mapped into physical memory)
- ; E=0 (data segment descriptor)
- ; D=0 (grow up segment, offsets must be <= limit)
- ; W=1 (data segment may be written into)
- ; DPL=0 (privilege level 0)
-
- GDT LABEL BYTE ;begin global descriptor table
- DESC <> ;dummy descriptor
- DESC <> ;descriptor for GDT itself
- SRC DESC <,,,93H,> ;source descriptor
- TGT DESC <,,,93H,> ;target descriptor
- DESC <> ;BIOS CS descriptor
- DESC <> ;stack segment descriptor
-
- SUBTTL INT 19H (boot) interrupt handler
- PAGE
- ;-----------------------------------------------------------------------;
- ; INT 19H Interrupt Handler routine ;
- ;-----------------------------------------------------------------------;
- ;The INT 19H vector is altered by VDISK initialization to point to this
- ;routine within the first extended memory VDISK device driver.
-
- ;The vector points to the device driver so that subsequent VDISKs installed
- ;in extended memory can find the first one to determine what memory has
- ;already been allocated to VDISKs.
-
- ;This routine restores the original INT 19H vector's content, then jumps
- ;to the original routine.
-
- ;INT 19H, the "Boot" INT, is always altered when DOS is booted.
-
- ;This routine is entered with interrupts disabled.
-
- VDISK_INT19 PROC ;INT 19H received
- PUSH DS ;save registers we're going to alter
- PUSH AX
-
- XOR AX,AX
- MOV DS,AX ;set DS = 0
- ASSUME DS:INT_VEC
-
- MOV AX,CS:INTV19O ;get offset of saved vector
- MOV DS:BOOT_VECO,AX ;store offset in interrupt vector
-
- MOV AX,CS:INTV19S ;get segment of saved vector
- MOV DS:BOOT_VECS,AX ;store segment in interrupt vector
-
- POP AX
- POP DS
-
- JMP CS:INTV19 ;go to original interrupt routine
-
- VDISK_INT19 ENDP
-
- ASSUME DS:NOTHING
-
- SUBTTL Device Strategy & interrupt entry points
- PAGE
- ;-----------------------------------------------------------------------;
- ; Device "strategy" entry point ;
- ; ;
- ; Retain the Request Header address for use by Interrupt routine ;
- ;-----------------------------------------------------------------------;
- STRATEGY PROC FAR
- MOV CS:RH_PTRO,BX ;offset
- MOV CS:RH_PTRS,ES ;segment
- RET
- STRATEGY ENDP
- ;-----------------------------------------------------------------------;
- ; Table of command processing routine entry points ;
- ;-----------------------------------------------------------------------;
- CMD_TABLE LABEL WORD
- DW OFFSET INIT_P1 ; 0 - Initialization
- DW OFFSET MEDIA_CHECK ; 1 - Media check
- DW OFFSET BLD_BPB ; 2 - Build BPB
- DW OFFSET INPUT_IOCTL ; 3 - IOCTL input
- DW OFFSET INPUT ; 4 - Input
- DW OFFSET INPUT_NOWAIT ; 5 - Non destructive input no wait
- DW OFFSET INPUT_STATUS ; 6 - Input status
- DW OFFSET INPUT_FLUSH ; 7 - Input flush
- DW OFFSET OUTPUT ; 8 - Output
- DW OFFSET OUTPUT_VERIFY ; 9 - Output with verify
- DW OFFSET OUTPUT_STATUS ;10 - Output status
- DW OFFSET OUTPUT_FLUSH ;11 - Output flush
- DW OFFSET OUTPUT_IOCTL ;12 - IOCTL output
- DW OFFSET DEVICE_OPEN ;13 - Device OPEN
- DW OFFSET DEVICE_CLOSE ;14 - Device CLOSE
- MAX_CMD EQU ($-CMD_TABLE)/2 ;highest valid command follows
- DW OFFSET REMOVABLE_MEDIA ;15 - Removable media
-
- ;-----------------------------------------------------------------------;
- ; Device "interrupt" entry point ;
- ;-----------------------------------------------------------------------;
- IRPT PROC FAR ;device interrupt entry point
- PUSH DS ;save all registers modified
- PUSH ES
- PUSH AX
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH DI
- PUSH SI
- ;BP isn't used, so it isn't saved
- CLD ;all moves forward
-
- LDS BX,CS:RH_PTRA ;get RH address passed to "strategy" into DS:BX
-
- MOV AL,RH.RHC_CMD ;command code from Request Header
- CBW ;zero AH (if AL > 7FH, next compare will
- ;catch that error)
- CMP AL,MAX_CMD ;if command code is too high
- JA IRPT_CMD_HIGH ;jump to error routine
-
- MOV DI,OFFSET IRPT_CMD_EXIT ;return addr from command processor
- PUSH DI ;push return address onto stack
- ;command routine issues "RET"
-
- ADD AX,AX ;double command code for table offset
- MOV DI,AX ;put into index register for JMP
-
- XOR AX,AX ;initialize return to "no error"
-
- ;At entry to command processing routine:
-
- ; DS:BX = Request Header address
- ; CS = VDISK code segment address
- ; AX = 0
-
- ; top of stack is return address, IRPT_CMD_EXIT
-
- JMP CS:CMD_TABLE[DI] ;call routine to handle the command
-
-
- IRPT_CMD_ERROR: ;CALLed for unsupported character mode commands
-
- INPUT_IOCTL: ;IOCTL input
- INPUT_NOWAIT: ;Non-destructive input no wait
- INPUT_STATUS: ;Input status
- INPUT_FLUSH: ;Input flush
-
- OUTPUT_IOCTL: ;IOCTL output
- OUTPUT_STATUS: ;Output status
- OUTPUT_FLUSH: ;Output flush
-
- POP AX ;pop return address off stack
-
- IRPT_CMD_HIGH: ;JMPed to if RHC_CMD > MAX_CMD
- MOV AX,STAT_CMDERR ;"invalid command" and error
-
- IRPT_CMD_EXIT: ;return from command routine
- ;AX = value to OR into status word
- LDS BX,CS:RH_PTRA ;restore DS:BX as Request Header pointer
- OR AH,STAT_DONE ;add "done" bit to status word
- MOV RH.RHC_STA,AX ;store status into request header
- POP SI ;restore registers
- POP DI
- POP DX
- POP CX
- POP BX
- POP AX
- POP ES
- POP DS
- RET
- IRPT ENDP
-
- SUBTTL Command Processing routines
- PAGE
- ;-----------------------------------------------------------------------;
- ; Command Code 1 - Media Check ;
- ; At entry, DS:BX point to request header, AX = 0 ;
- ;-----------------------------------------------------------------------;
- MEDIA_CHECK PROC
- MOV RH.RH1_RET,1 ;indicate media not changed
- RET ;AX = zero, no error
- MEDIA_CHECK ENDP
- ;-----------------------------------------------------------------------;
- ; Command Code 2 - Build BPB ;
- ; At entry, DS:BX point to request header, AX = 0 ;
- ;-----------------------------------------------------------------------;
- BLD_BPB PROC
- MOV RH.RH2_BPBO,OFFSET BPB ;return pointer to our BPB
- MOV RH.RH2_BPBS,CS
- RET ;AX = zero, no error
- BLD_BPB ENDP
- ;-----------------------------------------------------------------------;
- ; Command Code 13 - Device Open ;
- ; Command Code 14 - Device Close ;
- ; Command Code 15 - Removable media ;
- ; At entry, DS:BX point to request header, AX = 0 ;
- ;-----------------------------------------------------------------------;
- REMOVABLE_MEDIA PROC
- MOV AX,STAT_BUSY ;set status bit 9 (busy)
- ;indicating non-removable media
- DEVICE_OPEN: ;NOP for device open
- DEVICE_CLOSE: ;NOP for device close
- RET
- REMOVABLE_MEDIA ENDP ;fall thru to return
- ;-----------------------------------------------------------------------;
- ; Command Code 4 - Input ;
- ; Command Code 8 - Output ;
- ; Command Code 9 - Output with verify ;
- ; At entry, DS:BX point to request header, AX = 0 ;
- ;-----------------------------------------------------------------------;
- INOUT PROC
- INPUT:
- OUTPUT:
- OUTPUT_VERIFY:
-
- ;Make sure I/O is entirely within the VDISK sector boundaries
-
- MOV CX,CS:BPB_SECN ;get total sector count
- MOV AX,RH.RH4_SSN ;starting sector number
- CMP AX,CX ;can't exceed total count
- JA INOUT_E1 ;jump if start > total
-
- ADD AX,RH.RH4_CNT ;start + sector count
- CMP AX,CX ;can't exceed total count
- JNA INOUT_A ;jump if start + count <= total
- INOUT_E1: ;I/O not within VDISK sector boundaries
- MOV RH.RH4_CNT,0 ;set sectors transferred to zero
- MOV AX,STAT_SNF ;indicate 'Sector not found' error
- RET ;return with error status in AX
-
- INOUT_A: ;I/O within VDISK bounds
- MOV AX,RH.RH4_CNT ;get sector count
- MOV CS:SECT_LEFT,AX ;save as sectors left to process
-
- CMP CS:EM_SW,0 ;extended memory mode?
- JNE INOUT_EM ;jump to extended memory I/O code
-
- ;Compute offset and segment of VDISK buffer for starting segment in CX:SI
-
- MOV AX,RH.RH4_SSN ;starting sector number
- MUL CS:PARAS_PER_SECTOR ;* length of one sector in paragraphs
- ADD AX,CS:START_BUFFER_PARA ;+ segment of VDISK buffer sector 0
- MOV CX,AX ;segment address to CX
- XOR SI,SI ;offset is zero
-
- ;Compute address of caller's Data Transfer Addr in DX:AX with smallest offset,
- ;so that there is no possibility of overflowing a 64KB boundary moving MAX_CNT
- ;sectors.
-
- MOV AX,PARA_SIZE ;16
- MUL RH.RH4_DTAS ;* segment of caller's DTA in DX,AX
- ADD AX,RH.RH4_DTAO ;+ offset of caller's DTA
- ADC DL,0 ;carry in from addition
- DIV CS:WPARA_SIZE ;AX is segment of caller's DTA
- ;DX is smallest offset possible
- ;AX:DX = DTA address
-
- ;AX:DX is caller's DTA segment:offset, CX:SI is VDISK buffer segment:offset
-
- ;If this is an OUTPUT request, exchange the source and target addresses
-
- CMP RH.RHC_CMD,CMD_INPUT ;INPUT operation?
- JE INOUT_B ;jump if INPUT operation
-
- XCHG AX,CX ;swap source and target segment
- XCHG DX,SI ;swap source and target offset
-
- INOUT_B: ;CX:SI is source, AX:DX is target
- MOV CS:IO_SRCS,CX ;save source segment
- MOV CS:IO_SRCO,SI ;save source offset
- MOV CS:IO_TGTS,AX ;save target segment
- MOV CS:IO_TGTO,DX ;save target offset
-
- JMP SHORT INOUT_E ;AX := SECT_LEFT, test for zero
- INOUT_C: ;SECT_LEFT in AX, non-zero
-
- ; Compute number of sectors to transfer in a single move,
- ; AX = minimum of (SECT_LEFT, MAX_CNT)
- ; MAX_CNT is the maximum number of sectors that can be moved without
- ; spanning a 64KB boundary (0FFFFH / Sector size, remainder truncated)
-
- MOV CX,CS:MAX_CNT ;MAX sectors with one move
- CMP AX,CX ;if SECT_LEFT cannot span 64KB boundary
- JBE INOUT_D ;then move SECT_LEFT sectors
-
- MOV AX,CX ;else move MAX_CNT sectors
- INOUT_D:
- SUB CS:SECT_LEFT,AX ;reduce number of sectors left to move
-
- ;Move AX sectors from source to target
-
- MUL CS:BPB_SSZ ;sectors * sector size = byte count
- ;(cannot overflow into DX)
- SHR AX,1 ;/2 = word count
- MOV CX,AX ;word count to CX for REP MOVSW
-
- LDS SI,CS:IO_SRCA ;source segment/offset to DS:SI
- LES DI,CS:IO_TGTA ;target segment/offset to ES:DI
-
- REP MOVSW ;move MOV_CNT sectors
-
- ;Update source and target paragraph addresses
- ;AX has number of words moved
-
- SHR AX,1 ;words moved / 8 = paragraphs moved
- SHR AX,1
- SHR AX,1
-
- ADD CS:IO_SRCS,AX ;add paragraphs moved to source segment
- ADD CS:IO_TGTS,AX ;add paragraphs moved to target segment
-
- ;Determine if more sectors need to be transferred
-
- INOUT_E: ;do while SECT_LEFT <> zero
- MOV AX,CS:SECT_LEFT ;get sectors left to transfer
- OR AX,AX ;set flags
- JNZ INOUT_C ;go back to transfer some sectors
- RET ;AX = zero, all sectors transferred
-
- SUBTTL Extended Memory I/O routine
- PAGE
- ;-----------------------------------------------------------------------;
- ; Extended Memory I/O routine ;
- ;-----------------------------------------------------------------------;
- INOUT_EM: ;Extended memory I/O routine
- ;change to larger stack
- MOV SI,SS ;save old SS in SI
- MOV DX,SP ;save old SP in DX
- CLI ;disable interrupts
- MOV AX,CS
- MOV SS,AX ;set SS = CS
- MOV SP,OFFSET EM_STACK ;point to new stack
- STI ;enable interrupts
- PUSH SI ;save old SS at top of new stack
- PUSH DX ;save old SP on new stack
-
- MOV SI,RH.RH4_DTAO ;caller's DTA offset
-
- ;Compute 24-bit address of VDISK sector in CX (hi) and SI (low)
-
- MOV AX,RH.RH4_SSN ;starting sector number
- MUL CS:BPB_SSZ ;* sector size = offset within buffer
- ADD AX,CS:START_EM_LO ;+ base address of this VDISK buffer
- ADC DL,CS:START_EM_HI
- MOV CX,DX ;save high byte
- MOV SI,AX ;save low word
-
- ;Compute 24-bit address of caller's DTA in DX (hi) and AX (low)
-
- MOV AX,PARA_SIZE ;16
- MUL RH.RH4_DTAS ;* segment of caller's DTA
- ADD AX,RH.RH4_DTAO ;+ offset of caller's DTA
- ADC DL,0 ;carry in from addition
-
- ;Caller's DTA address is in CX,SI, VDISK buffer address is in DX,AX.
-
- ;If this is an OUTPUT request, exchange the source and target addresses
-
- CMP RH.RHC_CMD,CMD_INPUT ;INPUT operation?
- JE INOUT_EM_B ;jump if INPUT operation
-
- XCHG DX,CX ;swap source and target high byte
- XCHG AX,SI ;swap source and target low word
-
- INOUT_EM_B: ;CX,SI is source, DX,AX is target
-
- MOV SRC.DESC_BASEL,SI ;low 16 bits of source address
- MOV SRC.DESC_BASEH,CL ;high 8 bits of source address
-
- MOV TGT.DESC_BASEL,AX ;low 16 bits of target address
- MOV TGT.DESC_BASEH,DL ;high 8 bits of target address
-
- JMP SHORT INOUT_EM_E ;AX := SECT_LEFT, test for zero
- INOUT_EM_C: ;SECT_LEFT in AX, non-zero
-
- ; Compute number of sectors to transfer in a single move,
- ; AX = minimum of (SECT_LEFT, MAX_CNT)
-
- ; MAX_CNT is the maximum number of sectors that can be moved without
- ; spanning a 64KB boundary (0FFFFH / Sector size, remainder truncated)
-
- MOV CX,CS:MAX_CNT ;MAX sectors with one move
- CMP AX,CX ;if SECT_LEFT cannot span 64KB boundary
- JBE INOUT_EM_D ;then move SECT_LEFT sectors
-
- MOV AX,CX ;else move MAX_CNT sectors
- INOUT_EM_D:
- SUB CS:SECT_LEFT,AX ;reduce number of sectors left to move
-
- ;Move AX sectors from source to target
-
- MUL CS:BPB_SSZ ;sectors * sector size = byte count
- ;(cannot overflow into DX)
- MOV TGT.DESC_LMT,AX ;store segment limit (byte count)
- MOV SRC.DESC_LMT,AX
-
- PUSH AX ;preserve byte count on stack
-
- SHR AX,1 ;/2 = word count
- MOV CX,AX ;word count to CX
-
- PUSH CS
- POP ES ;set ES = CS
- MOV SI,OFFSET GDT ;ES:SI point to GDT
-
- MOV AH,EM_BLKMOVE ;function is block move
- INT EM_INT ;move an even number of words
-
- POP CX ;get byte count back from stack
-
- OR AH,AH ;get error code
-
- JNZ INOUT_EM_XE ;jump if I/O error encountered
-
- ;Update source and target addresses
-
- ADD SRC.DESC_BASEL,CX ;add bytes moved to source
- ADC SRC.DESC_BASEH,0 ;pick up any carry
-
- ADD TGT.DESC_BASEL,CX ;add bytes moved to target
- ADC TGT.DESC_BASEH,0 ;pick up any carry
-
- ;Determine if more sectors need to be transferred
-
- INOUT_EM_E: ;do while SECT_LEFT <> zero
- MOV AX,CS:SECT_LEFT ;get sectors left to transfer
- OR AX,AX ;set flags
- JNZ INOUT_EM_C ;go back to transfer some sectors
-
- INOUT_EM_X2: ;revert to original stack
- POP DI ;get old SP
- POP SI ;get old SS
- CLI ;disable interrupts
- MOV SS,SI ;restore old SS
- MOV SP,DI ;restore old SP
- STI ;enable interrupts
- RET ;return to IRPT_EXIT
-
- INOUT_EM_XE: ;some error with INT 15H
- MOV CS:EM_STAT,AX ;save error status for debugging
- MOV RH.RH4_CNT,0 ;indicate no sectors transferred
- MOV AX,STAT_CRC ;indicate CRC error
- JMP INOUT_EM_X2 ;fix stack and exit
- INOUT ENDP
-
- DW 40 DUP (?) ;stack for extended memory I/O
-
- EM_STACK LABEL WORD
-
- SUBTTL Boot Record
- PAGE
- ;-----------------------------------------------------------------------;
- ; Adjust the assembly-time instruction counter to a paragraph ;
- ; boundary ;
- ;-----------------------------------------------------------------------;
-
- IF ($-START) MOD 16
- ORG ($-START) + 16 - (($-START) MOD 16)
- ENDIF
-
- VDISK EQU $ ;start of virtual disk buffer
- VDISKP EQU ($-START) / PARA_SIZE ;length of program in paragraphs
- ;-----------------------------------------------------------------------;
- ; If this VDISK is in extended memory, this address is passed ;
- ; back to DOS as the end address that is to remain resident. ;
- ; ;
- ; It this VDISK is not in extended memory, the VDISK buffer ;
- ; begins at this address, and the address passed back to DOS ;
- ; as the end address that is to remain resident is this address ;
- ; plus the length of the VDISK buffer. ;
- ;-----------------------------------------------------------------------;
-
- BOOT_RECORD LABEL BYTE ;Format of Boot Record documented in
- ;DOS Technical Reference Manual
- DB 0,0,0 ;3-byte jump to boot code (not bootable)
- DB 'VDISK1.0' ;8-byte vendor identification
-
- BOOT_BPB LABEL BYTE ;boot record copy of BIOS parameter block
- DW ? ;number of bytes per disk sector
- DB ? ;sectors per allocation unit
- DW ? ;number of reserved sectors (for boot record)
- DB ? ;number of File Allocation Table (FAT) copies
- DW ? ;number of root directory entries
- DW ? ;total number of sectors
- DB ? ;media descriptor byte
- DW ? ;number of sectors occupied by a single FAT
- ;end of boot record BIOS Parameter block
-
- ;The following three words mean nothing to VDISK, they are placed here
- ;to conform to the DOS standard for boot records.
- DW 8 ;sectors per track
- DW 1 ;number of heads
- DW 0 ;number of hidden sectors
- ;The following word is the 16-bit kilobyte address of the first byte in
- ;extended memory that is not occupied by a VDISK buffer
- ;It is placed into this location so that other users of extended memory
- ;may find where all the VDISKs end.
-
- ;This field may be accessed by moving the boot record of the First extended
- ;memory VDISK from absolute location 10 0000H. Before assuming that the
- ;value below is valid, the vendor ID (constant VDISK) should be verified
- ;to make sure that SOME VDISK has been installed.
-
- ;For example, if two VDISKs are installed, one 320KB and one 64KB, the
- ;address calculations are as follows:
-
- ;Extended memory start address = 100000H (1024KB)
- ;Start addr of 1st VDISK buffer = 100000H (1024KB)
- ;Length of 1st VDISK buffer = 050000H ( 320KB)
- ;End addr of 1st VDISK buffer = 14FFFFH
- ;Start addr of 2nd VDISK buffer = 150000H (1344KB)
- ;Length of 2nd VDISK buffer = 010000H ( 64KB)
- ;End addr of 2nd VDISK buffer = 15FFFFH
- ;First byte after all VDISKs = 160000H (1408KB)
- ;Divide by 1024 = 0580H (1408D)
-
- ;Content of BOOT_EM = 0580H
-
- BOOT_EM_OFF EQU $-BOOT_RECORD ;offset from 10 0000H of the following word
- BOOT_EM DW 1024 ;KB addr of first free byte of extended memory
- ;-----------------------------------------------------------------------;
- ; Part 2 of Initialization (executed last) ;
- ;-----------------------------------------------------------------------;
- ;Initialization is divided into two parts.
-
- ;INIT_P1 is overlaid by the virtual disk buffer
-
- ;INIT_P1 is executed first, then jumps to INIT_P2. INIT_P2 returns to caller.
-
- ;Exercise caution if extending the initialization part 2 code.
- ;It overlays the area immediately following the boot sector.
- ;If this section of code must be expanded, make sure it fits into the minimum
- ;sector size of 128 bytes.
- ;Label TEST_LENGTH must equate to a non-negative value (TEST_LENGTH >= 0).
- ;If this code it must be extended beyond the 128 byte length of the boot sector,
- ;move all of INIT_P2 before label VDISK.
-
- ;Registers at entry to INIT_P2 (set up at end of INIT_P1):
- ; BL = media control byte from BPB (for FAT)
- ; CX = number of FAT copies
- ; DX = number of bytes in one FAT - 3
- ; SI = OFFSET of Volume Label field
- ; ES:DI = VDISK buffer address of first FAT sector
- ; CS = DS = VDISK code segment
-
- INIT_P2 PROC ;second part of initialization
- ASSUME DS:CSEG ;DS set in INIT_P1
-
- ;Initialize File Allocation Table(s) (FATs)
-
- INIT_P2_FAT: ;set up one FAT, sector number in AX
-
- PUSH CX ;save loop counter on stack
- MOV AL,BL ;media control byte
- STOSB ;store media control byte, increment DI
- MOV AX,0FFFFH ;bytes 2 and 3 of FAT are 0FFH
- STOSW
-
- MOV CX,DX ;FAT size in bytes - 3
- XOR AX,AX ;value to store in remainder of FAT
- REP STOSB ;clear remainder of FAT
-
- POP CX ;get loop counter off stack
- LOOP INIT_P2_FAT ;loop for all copies of the FAT
-
- ;Put the volume label in the first directory entry
-
- MOV CX,VOL_LABEL_LEN ;length of volume directory entry
- REP MOVSB ;move volume id to directory
-
- ;Zero the remainder of the directory
-
- MOV AX,DIR_ENTRY_SIZE ;length of 1 directory entry
- MUL BPB_DIRN ;* number entries = bytes of directory
- SUB AX,VOL_LABEL_LEN ;less length of volume label
- MOV CX,AX ;length of rest of directory
- XOR AX,AX
- REP STOSB ;clear directory to nulls
- RET ;return with AX=0
- INIT_P2 ENDP
-
- PATCH_AREA DB 5 DUP ('PATCH AREA ')
-
- TEST_LENGTH EQU 128-($-VDISK) ;if negative, boot record has too much
- ;data area, move some fields below VDISK
- ;-----------------------------------------------------------------------;
- ; All fields that must remain resident after device driver ;
- ; initialization must be defined before this point. ;
- ;-----------------------------------------------------------------------;
- DB 'The IBM Personal Computer Virtual Disk Device Driver, '
- DB 'Version 1.00 (C)Copyright IBM Corp 1984'
- DB 'Licensed Material - Program Property of IBM. '
- DB 'Author: Dick Dievendorff '
-
- BUFF_SIZE DW 0 ;desired VDISK buffer size in kilobytes
-
- MIN_MEMORY_LEFT DW 64 ;minimum amount of system memory (kilobytes)
- ;that must remain after VDISK is installed
-
- FIRST_EM_SW DB ? ;0FFH if this is the first device driver
- ;to be installed in extended memory
- ;00H if another VDISK extended memory driver
- ;has been installed
-
- FIRST_VDISK DW ? ;segment address of 1st VDISK device driver
- PARA_PER_KB DW 1024/PARA_SIZE ;paragraphs in one kilobyte
- C1024 DW 1024 ;bytes in one kilobyte
- DIRE_SIZE DW DIR_ENTRY_SIZE ;bytes in one directory entry
- DIR_SECTORS DW ? ;number of sectors of directory
-
- ERR_FLAG DB 0 ;error indicators to condition messages
- ERR_BSIZE EQU 80H ;buffer size adjusted
- ERR_SSZ EQU 40H ;sector size adjusted
- ERR_DIRN EQU 20H ;number of directory entries adjusted
- ERR_PASS EQU 10H ;some adjustment made that requires
- ;recomputation of values previously computed
- ERR_SSZB EQU ERR_SSZ+ERR_PASS ;sector size altered this pass
- ERR_SYSSZ EQU 08H ;system storage too small for VDISK
- ERR_SWTCH EQU 04H ;invalid switch character
- ERR_EXTSW EQU 02H ;extender card switches don't match memory size
-
-
- SUBTTL Initialization, Part one
- PAGE
- ;-----------------------------------------------------------------------;
- ; Command Code 0 - Initialization ;
- ; At entry, DS:BX point to request header, AX = 0 ;
- ;-----------------------------------------------------------------------;
- ;Initialization is divided into two parts.
- ;This part, executed first, is later overlaid by the VDISK buffer.
-
- INIT_P1 PROC ;first part of initialization
- MOV DX,SS ;save stack segment register
- MOV CX,SP ;save stack pointer register
- CLI ;inhibit interrupts while changing SS:SP
- MOV AX,CS ;move CS to SS through AX
- MOV SS,AX
- MOV SP,OFFSET MSGEND ;end of VDISKMSG
- ADD SP,STACK_SIZE ;+ length of our stack
- STI ;allow interrupts
- PUSH DX ;save old SS register on new stack
- PUSH CX ;save old SP register on new stack
-
- CALL GET_PARMS ;get parameters from CONFIG.SYS line
-
- PUSH CS
- POP DS ;set DS = CS
- ASSUME DS:CSEG
-
- CALL APPLY_DEFAULTS ;supply any values not specified
- CALL DETERMINE_START ;compute start address of VDISK buffer
- CALL VALIDATE ;validate parameters
- CALL COPY_BPB ;Copy BIOS Parameter Block to boot record
-
- CALL VERIFY_EXTENDER ;Verify that extender card switches are right
- TEST ERR_FLAG,ERR_EXTSW ;are switches wrong?
- JNZ INIT_P1_A ;if so, exit with messages
-
- CMP EM_SW,0 ;extended memory requested?
- JE INIT_P1_A ;jump if not
-
- TEST ERR_FLAG,ERR_SYSSZ ;is system too small for VDISK?
- JNZ INIT_P1_A ;if so, don't do extended memory init
-
- CALL UPDATE_AVAIL ;update AVAIL_HI and AVAIL_LO to reflect
- ;addition of extended memory VDISK
- CALL FORMAT_VDISK ;construct a boot record, FATs and
- ;directory in storage immediately
- ;following this device driver
- CALL MOVE_VDISK ;move formatted boot record, FATs,
- ;and directory to extended memory
- CALL UPDATE_BOOT ;place the end address of ALL VDISKs
- ;in the boot record of the first VDISK
- CMP FIRST_EM_SW,0 ;is this the first extended memory VDISK?
- JE INIT_P1_A ;no, exit
-
- CALL STEAL_INT19 ;point INT 19H to this VDISK
- INIT_P1_A:
- CALL FILL_RH ;fill in INIT request header
- CALL WRITE_MESSAGES ;display all messages
- POP CX ;get old SP from stack
- POP DX ;get old SS from stack
- CLI ;disable interrupts while changing SS:SP
- MOV SS,DX ;restore stack segment register
- MOV SP,CX ;restore stack pointer register
- STI ;enable interrupts
- ;-----------------------------------------------------------------------;
- ; INIT_P2 must be short enough to fit into the boot sector ;
- ; (minimum size of boot sector is 128 bytes), so we set up ;
- ; as many pointers as we can to help keep INIT_P2 short. ;
- ; ;
- ; ES:DI = storage address of first FAT sector ;
- ; BL = media control byte ;
- ; CX = number of FAT copies ;
- ; DX = number of bytes in one FAT, less 3 ;
- ; SI = offset of VOL label field ;
- ;-----------------------------------------------------------------------;
- MOV ES,START_BUFFER_PARA ;start paragraph of VDISK buffer
-
- MOV AX,BPB_RES ;number of reserved sectors
- MUL BPB_SSZ ;* sector size
- MOV DI,AX ;ES:DI point to FAT start
-
- MOV BL,BPB_MCB ;media control byte
-
- MOV CL,BPB_FATN ;number of FAT copies
- XOR CH,CH
-
- MOV AX,BPB_FATSZ ;FAT size in sectors
- MUL BPB_SSZ ;* sector size = total FAT bytes
-
- SUB AX,3 ;-3 (FEFFFF stored by code)
- MOV DX,AX
-
- MOV SI,OFFSET VOL_LABEL ;point to VOL label directory entry
- JMP INIT_P2 ;jump to second part of initialization
- ;this is redundant if the VDISK is in
- ;extended memory, but is executed anyway
-
- SUBTTL GET_PARMS Parameter Line Scan
- PAGE
- ;-----------------------------------------------------------------------;
- ;GET_PARMS gets the parameters from the CONFIG.SYS statement ;
- ; ;
- ;Register usage: ;
- ; DS:SI indexes parameter string ;
- ; AL contains character from parameter string ;
- ; CX value from GET_NUMBER ;
- ;-----------------------------------------------------------------------;
- ASSUME DS:NOTHING ;DS:BX point to Request Header
- GET_PARMS PROC ;get parameters from CONFIG.SYS line
- PUSH DS ;save DS
- LDS SI,RH.RH0_BPBA ;DS:SI point to all after DEVICE=
- ;in CONFIG.SYS line
- XOR AL,AL ;not at end of line
-
- ;Skip until first delimiter is found. There may be digits in the path string.
-
- ;DS:SI points to \pathstring\VDISK.SYS nn nn nn
- ;The character following VDISK.SYS may have been changed to a null (00H).
- ;All letters have been changed to uppercase.
-
- GET_PARMS_A: ;skip to DOS delimiter character
- CALL GET_PCHAR ;get parameter character into AL
- JZ GET_PARMS_X ;get out if end of line encountered
- OR AL,AL ;test for null
- JZ GET_PARMS_B
- CMP AL,' '
- JE GET_PARMS_B
- CMP AL,','
- JE GET_PARMS_B
- CMP AL,';'
- JE GET_PARMS_B
- CMP AL,'+'
- JE GET_PARMS_B
- CMP AL,'='
- JE GET_PARMS_B
- CMP AL,TAB
- JNE GET_PARMS_A ;skip until delimiter or CR
-
- GET_PARMS_B: ;now pointing to first delimiter
- PUSH SI ;save pointer, used to rescan for /E
- CALL SKIP_TO_DIGIT ;skip to first digit
- JZ GET_PARMS_C ;found EOL, no digits remain
-
- CALL GET_NUMBER ;extract digits, convert to binary
- MOV CS:BUFF_SIZE,CX ;store buffer size
-
- CALL SKIP_TO_DIGIT ;skip to next digit
- JZ GET_PARMS_C ;found EOL, no digits remain
-
- CALL GET_NUMBER ;extract digits, convert to binary
- MOV CS:BPB_SSZ,CX ;store sector size
-
- CALL SKIP_TO_DIGIT ;skip to next digit
- JZ GET_PARMS_C ;found EOL, no digits remain
-
- CALL GET_NUMBER ;extract digits, convert to binary
- MOV CS:BPB_DIRN,CX ;store number of directory entries
- GET_PARMS_C:
- POP SI ;set for rescan for /E
- XOR AL,AL ;not at EOL now
- MOV CS:EM_SW,0 ;indicate no /E found
- GET_PARMS_D: ;scan for /
- CALL GET_PCHAR
- JZ GET_PARMS_X ;exit if end of line
-
- CMP AL,'/' ;found slash?
- JNE GET_PARMS_D ;no, continue scan
-
- CALL GET_PCHAR ;get char following slash
- CMP AL,'E' ;don't have to test for lower case E,
- ;letters have been changed to upper case
- JNE GET_PARMS_E ;not 'E'
-
- MOV CS:EM_SW,AL ;indicate /E found
- JMP GET_PARMS_D ;continue forward scan
-
- GET_PARMS_E: ;/ found, not 'E'
- OR CS:ERR_FLAG,ERR_SWTCH ;indicate invalid switch character
- JMP GET_PARMS_D ;continue scan
- GET_PARMS_X: ;premature end of line
- POP DS ;restore DS
- RET
-
-
- GET_PCHAR PROC ;internal proc to get next character into AL
- CMP AL,CR ;carriage return already encountered?
- JE GET_PCHAR_X ;don't read past end of line
- LODSB ;get char from DS:SI, increment SI
- CMP AL,CR ;is the char a carriage return?
- JE GET_PCHAR_X ;yes, set Z flag at end of line
- CMP AL,LF ;no, is it a line feed?
- GET_PCHAR_X: ;attempted read past end of line
- RET
- GET_PCHAR ENDP ;returns char in AL
-
-
- CHECK_NUM PROC ;check AL for ASCII digit
- CMP AL,'0' ;< '0'?
- JB CHECK_NUM_X ;exit if it is
-
- CMP AL,'9' ;> '9'?
- JA CHECK_NUM_X ;exit if it is
-
- CMP AL,AL ;set Z flag to indicate numeric
-
- CHECK_NUM_X:
- RET ;Z set if numeric, NZ if not numeric
- CHECK_NUM ENDP
-
-
- SKIP_TO_DIGIT PROC ;skip to first numeric character
- CALL CHECK_NUM ;is current char a digit?
- JZ SKIP_TO_DIGIT_X ;if so, skip is complete
-
- CALL GET_PCHAR ;get next character from line
- JNZ SKIP_TO_DIGIT ;loop until first digit or CR or LF
- RET ;character is CR or LF
-
- SKIP_TO_DIGIT_X:
- CMP AL,0 ;digit found, force NZ
- RET
- SKIP_TO_DIGIT ENDP
-
- C10 DW 10
- GN_ERR DB ? ;zero if no overflow in accumulation
-
- GET_NUMBER PROC ;convert string of digits to binary value
- XOR CX,CX ;accumulate number in CX
- MOV CS:GN_ERR,CL ;no overflow yet
- GET_NUMBER_A: ;accumulate next digit
- SUB AL,'0' ;convert ASCII to binary
- CBW ;clear AH
- XCHG AX,CX ;previous accumulation in AX, new digit in CL
- MUL CS:C10 ;DX:AX := AX*10
- OR CS:GN_ERR,DL ;set GN_ERR <> 0 if overflow
- ADD AX,CX ;add new digit from
- XCHG AX,CX ;number now in CX
- CALL GET_PCHAR ;get next character
- CALL CHECK_NUM ;see if it was numeric
- JZ GET_NUMBER_A ;continue accumulating
- CMP CS:GN_ERR,0 ;did we overflow?
- JE GET_NUMBER_B ;if not, we're done
- XOR CX,CX ;return zero (always invalid) if overflow
- GET_NUMBER_B:
- RET ;number in CX, next char in AL
- GET_NUMBER ENDP
-
- GET_PARMS ENDP
-
- SUBTTL APPLY_DEFAULTS
- PAGE
- ;-----------------------------------------------------------------------;
- ; APPLY_DEFAULTS supplies any parameter values that the user ;
- ; failed to specify ;
- ;-----------------------------------------------------------------------;
- ASSUME DS:CSEG
- APPLY_DEFAULTS PROC
- XOR AX,AX
- CMP BUFF_SIZE,AX ;is buffer size zero?
- JNE APPLY_DEFAULTS_A ;no, user specified something
-
- MOV BUFF_SIZE,DFLT_BSIZE ;supply default buffer size
- OR ERR_FLAG,ERR_BSIZE ;indicate buffersize adjusted
-
- APPLY_DEFAULTS_A:
- CMP BPB_SSZ,AX ;is sector size zero?
- JNE APPLY_DEFAULTS_B ;no, user specified something
-
- MOV BPB_SSZ,DFLT_SSZ ;supply default sector size
- OR ERR_FLAG,ERR_SSZ ;indicate sector size adjusted
-
- APPLY_DEFAULTS_B:
- CMP BPB_DIRN,AX ;are directory entries zero?
- JNE APPLY_DEFAULTS_C ;no, user specified something
-
- MOV BPB_DIRN,DFLT_DIRN ;supply default directory entries
- OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted
-
- APPLY_DEFAULTS_C:
- RET
- APPLY_DEFAULTS ENDP
-
- SUBTTL DETERMINE_START address of VDISK buffer
- PAGE
- ;-----------------------------------------------------------------------;
- ; DETERMINE_START figures out the starting address of the VDISK ;
- ; buffer ;
- ;-----------------------------------------------------------------------;
- ASSUME DS:CSEG
- DETERMINE_START PROC
-
- ;If extended memory is NOT being used, the VDISK buffer immediately
- ;follows the resident code.
-
- ;If extended memory IS being used, START_BUFFER_PARA becomes the
- ;end of device driver address passed back to DOS.
-
- MOV AX,CS ;start para of VDISK code
- ADD AX,VDISKP ;+ length of resident code
- MOV START_BUFFER_PARA,AX ;save as buffer start para
-
- CMP EM_SW,0 ;is extended memory requested?
- JE DETERMINE_START_X ;if not, we're done here
-
- ;If this is the first extended memory VDISK device driver to be installed,
- ;the start address for I/O is 1 megabyte.
-
- ;If one or more extended memory VDISK device drivers have been installed,
- ;the start address for I/O for THIS device driver is acquired from the
- ;fields AVAIL_LO and AVAIL_HI in the FIRST VDISK device driver.
-
- ;The first extended memory VDISK device driver is located by INT 19H's vector.
-
- MOV FIRST_EM_SW,0FFH ;indicate first VDISK device driver
- MOV FIRST_VDISK,CS ;segment addr of first VDISK
-
- PUSH DS ;preserve DS
- XOR AX,AX
- MOV DS,AX ;set DS = 0
- ASSUME DS:INT_VEC
-
- MOV AX,DS:BOOT_VECS ;get segment addr of INT 19H routine
- MOV DS,AX ;to DS
- ASSUME DS:NOTHING
-
- PUSH CS
- POP ES ;set ES = CS
- MOV SI,OFFSET VOL_LABEL ;DS:SI point to VOL label field
- ;in first VDISK (if present)
- MOV DI,SI ;ES:DI point to VOL label field of
- ;this VDISK
-
- MOV CX,VOL_LABEL_LEN ;length of volume label
- REP CMPSB ;does INT 19H vector point to a VDISK
- ;device driver?
- JNE DETERMINE_START_A ;jump if this is the first VDISK
-
- ;Another extended memory VDISK device driver has been installed.
- ;Its AVAIL_LO and AVAIL_HI are the first free byte of extended memory.
-
- MOV CS:FIRST_EM_SW,0 ;indicate not first device driver
- MOV CS:FIRST_VDISK,DS ;save pointer to 1st device driver
-
- ;Copy AVAIL_LO and AVAIL_HI from first VDISK to this VDISK
-
- MOV SI,OFFSET AVAIL_LO ;DS:SI point to AVAIL_LO in first VDISK
- MOV DI,SI ;ES:DI point to AVAIL_LO in this VDISK
- MOVSW ;copy AVAIL_LO from first to this VDISK
- MOVSB ;copy AVAIL_HI
-
- DETERMINE_START_A: ;copy AVAIL_LO and AVAIL_HI to START_EM
- POP DS ;set DS = CS
-
- MOV SI,OFFSET AVAIL_LO ;source offset
- MOV DI,OFFSET START_EM_LO ;destination offset
-
- MOVSW ;move AVAIL_LO to START_EM_LO
- MOVSB ;move AVAIL_HI to START_EM_HI
- DETERMINE_START_X:
- RET
- DETERMINE_START ENDP
-
- SUBTTL VALIDATE parameters
- PAGE
- ;-----------------------------------------------------------------------;
- ; VALIDATE adjusts parameters as necessary ;
- ;-----------------------------------------------------------------------;
- VAL_SSZ_TBL LABEL WORD ;table of valid sector sizes
- VAL_SSZ_S DW 128 ;smallest valid sector size
- DW 256
- VAL_SSZ_L DW 512 ;largest valid sector size
- VAL_SSZ_N EQU ($-VAL_SSZ_TBL)/2 ;number of table entries
-
- ASSUME DS:CSEG
- VALIDATE PROC ;validate parameters
- MOV BPB_AUSZ,1 ;initial allocation unit is 1 sector
-
- CALL VAL_BSIZE ;validate buffer size
-
- CALL VAL_SSZ ;validate (adjust if necessary) BPB_SSZ
-
- VALIDATE_A:
- AND ERR_FLAG,255-ERR_PASS ;indicate nothing changed this pass
-
- MOV AX,BPB_SSZ ;sector size
- CWD ;clear DX for division
- DIV WPARA_SIZE ;sector size/para size
- MOV PARAS_PER_SECTOR,AX ;number of paragraphs/sector
-
- MOV AX,BUFF_SIZE ;requested buffersize in KB
- MUL C1024 ;DX:AX = buffer size in bytes
- DIV BPB_SSZ ;/sector size = # sectors
- MOV BPB_SECN,AX ;store number of sectors
-
- CALL VAL_DIRN ;validate number of directory entries
-
- TEST ERR_FLAG,ERR_PASS ;may have reset sector size
- JNZ VALIDATE_A ;recompute directory & FAT sizes
-
- CALL VAL_FAT ;compute FAT entries, validity test
-
- TEST ERR_FLAG,ERR_PASS ;if cluster size altered this pass
- JNZ VALIDATE_A ;recompute directory & FAT sizes
-
- ;Make certain buffer size is large enough to contain:
- ; boot sector(s)
- ; FAT sector(s)
- ; directory sector(s)
- ; at least 1 data cluster
-
- MOV AL,BPB_FATN ;number of FAT copies
- CBW ;clear AH
- MUL BPB_FATSZ ;* sectors for 1 FAT = FAT sectors
- ADD AX,BPB_RES ;+ reserved sectors
- ADD AX,DIR_SECTORS ;+ directory sectors
- MOV CL,BPB_AUSZ ;get sectors/cluster
-
- XOR CH,CH ;CX = sectors in one cluster
- ADD AX,CX ;+ one data cluster
- CMP BPB_SECN,AX ;compare with sectors available
- JAE VALIDATE_X ;jump if enough sectors
-
- CMP DIR_SECTORS,1 ;down to 1 directory sector?
- JBE VALIDATE_C ;can't let it go below 1
-
- MOV AX,BPB_SSZ ;sector size
- CWD ;clear DX for division
- DIV DIRE_SIZE ;sectorsize/dir entry size = entries/sector
- SUB BPB_DIRN,AX ;reduce directory entries by 1 sector
-
- OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted
- JMP VALIDATE_A ;retry with new directory entries number
-
- VALIDATE_C: ;not enough space for any VDISK
- OR ERR_FLAG,ERR_SYSSZ
- VALIDATE_X:
- RET
-
- SUBTTL VAL_BSIZE Validate buffer size
- PAGE
- ;-----------------------------------------------------------------------;
- ; VAL_BSIZE adjusts the buffer size as necessary ;
- ;-----------------------------------------------------------------------;
- VAL_BSIZE PROC
- CALL GET_MSIZE ;determine memory available to VDISK
- ;returns available KB in AX
- OR AX,AX ;is any memory available at all?
- JNZ VAL_BSIZE_B ;yes, continue
-
- OR ERR_FLAG,ERR_SYSSZ ;indicate system too small for VDISK
- MOV BUFF_SIZE,1 ;set up minimal values to continue init
- MOV AX,VAL_SSZ_S ;smallest possible sector size
- MOV BPB_SSZ,AX
- MOV BPB_DIRN,4 ;4 directory entries
- RET
-
- VAL_BSIZE_B: ;some memory is available
- CMP AX,BUFF_SIZE ;is available memory >= requested?
- JAE VAL_BSIZE_C ;if so, we're done
-
- MOV BUFF_SIZE,AX ;give all available memory
- OR ERR_FLAG,ERR_BSIZE ;indicate buffersize adjusted
- VAL_BSIZE_C:
- RET
-
-
- GET_MSIZE PROC ;determine memory available to VDISK
- ;returns KB available in AX
- CMP EM_SW,0 ;extended memory?
- JE GET_MSIZE_2 ;use non-extended memory routine
-
- MOV AH,EM_MEMSIZE ;function code to AH
- INT EM_INT ;get extended memory size in AX
- JC GET_MSIZE_Z ;if error, no extended memory installed
-
- MUL C1024 ;DX,AX = bytes of extended memory
- ADD DX,10H ;DX,AX = high addr of extended memory+1
- SUB AX,AVAIL_LO ;- address of first available byte
- SBB DL,AVAIL_HI ;is number of free bytes
- DIV C1024 ;AX = number of whole free kilobytes
- RET
-
- GET_MSIZE_2: ;non-extended memory size determination
-
- ;Compute AX = total system size, - (VDISK end address + 64KB)
-
- MOV AX,START_BUFFER_PARA ;paragraph end of VDISK code
- XOR DX,DX ;clear for division
- DIV PARA_PER_KB ;KB address of load point
- ADD DX,0FFFFH ;round upward to KB boundary
- ADC AX,MIN_MEMORY_LEFT ;pick up CY and the 64KB we should leave
- PUSH AX ;save across interrupt
-
- INT MEM_SIZE ;get total system size
- POP DX ;amount of total that we can't use
- SUB AX,DX ;available space to VDISK
- JNC GET_MSIZE_X ;exit if positive
-
- GET_MSIZE_Z:
- XOR AX,AX ;indicate no memory available
- GET_MSIZE_X: ;exit from memory size determination
- RET
- GET_MSIZE ENDP
-
- VAL_BSIZE ENDP
-
- SUBTTL VAL_SSZ Validate Sector Size
- PAGE
- ;-----------------------------------------------------------------------;
- ; VAL_SSZ validates sector size, adjusting if necessary ;
- ;-----------------------------------------------------------------------;
- VAL_SSZ PROC ;validate sector size
- MOV BX,BPB_SSZ ;requested sector size
- MOV CX,VAL_SSZ_N ;number of table entries
- MOV SI,OFFSET VAL_SSZ_TBL ;DS:SI point to table start
- VAL_SSZ_A:
- LODSW ;get table entry, step table pointer
- CMP AX,BX ;is value in table?
- JE VAL_SSZ_X ;exit if value found
- LOOP VAL_SSZ_A ;loop until table end
-
- MOV BX,DFLT_SSZ ;get default sector size
- MOV BPB_SSZ,BX ;set sector size to default value
- OR ERR_FLAG,ERR_SSZ ;indicate sector size adjusted
- VAL_SSZ_X:
-
- ;Compute the maximum number of sectors that can be moved in 64KB (less one)
- ;Restricting moves to this amount avoids 64KB boundary problems.
-
- XOR DX,DX
- MOV AX,0FFFFH ;64KB - 1
- DIV BX ;/sector size
- MOV MAX_CNT,AX ;max sectors in one move
- RET
- VAL_SSZ ENDP
-
- SUBTTL VAL_DIRN Validate number of directory entries
- PAGE
- ;-----------------------------------------------------------------------;
- ; VAL_DIRN validates and adjusts the number of directory entries. ;
- ; ;
- ; Minimum is MIN_DIRN, maximum is MAX_DIRN. If outside these ;
- ; limits, DFLT_DIRN is used. ;
- ; ;
- ; The number of directory entries is rounded upward to fill ;
- ; a sector ;
- ;-----------------------------------------------------------------------;
- VAL_DIRN PROC
- MOV AX,BPB_DIRN ;requested directory entries
- CMP AX,MIN_DIRN ;if less than minimum
- JB VAL_DIRN_A ;use default instead
-
- CMP AX,MAX_DIRN ;if <= maximum
- JBE VAL_DIRN_B ;accept value as provided
-
- VAL_DIRN_A:
- MOV AX,DFLT_DIRN ;use default directory entries
- OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted
- VAL_DIRN_B: ;AX is number of directory entries
- MUL DIRE_SIZE ;* 32 = bytes of directory requested
- DIV BPB_SSZ ;/ sector size = # of directory sectors
- OR DX,DX ;test remainder for zero
- JZ VAL_DIRN_C ;jump if exact fit
-
- INC AX ;increment directory sectors
- OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted
- VAL_DIRN_C: ;make sure enough sectors available
- MOV DX,BPB_SECN ;total sectors on media
- SUB DX,BPB_RES ;less reserved sectors
- SUB DX,2 ;less minimum FAT and 1 data sector
- CMP AX,DX ;if directory sectors <= available
- JLE VAL_DIRN_D ;use requested amount
-
- MOV AX,1 ;use only one directory sector
- OR ERR_FLAG,ERR_DIRN ;indicate directory entries adjusted
- VAL_DIRN_D:
- MOV DIR_SECTORS,AX ;save number of directory sectors
- MUL BPB_SSZ ;dir sectors * sector size = dir bytes
- DIV DIRE_SIZE ;dir bytes / entry size = entries
- MOV BPB_DIRN,AX ;store adjusted directory entries
- RET
- VAL_DIRN ENDP
-
- SUBTTL VAL_FAT Validate File Allocation Table (FAT)
- PAGE
- ;-----------------------------------------------------------------------;
- ;VAL_FAT computes: ;
- ;BPB_FATSZ, the number of sectors required per FAT copy ;
- ; ;
- ;Each FAT entry is 12 bits long, for a maximum of 4095 FAT entries. ;
- ;(A few FAT entries are reserved, so the highest number of FAT entries ;
- ;we permit is 0FE0H.) With large buffer sizes and small sector sizes, ;
- ;we have more allocation units to describe than a 12-bit entry will ;
- ;describe. If the number of FAT entries is too large, the sector size ;
- ;is increased (up to a maximum of 512 bytes), and then the allocation ;
- ;unit (cluster) size is doubled, until we have few enough allocation ;
- ;units to be properly described in 12 bits. ;
- ; ;
- ;This computation is slightly conservative in that the FAT entries ;
- ;necessary to describe the FAT sectors are included in the computation. ;
- ;-----------------------------------------------------------------------;
- VAL_FAT PROC
- MOV AX,BPB_SECN ;total number of sectors
- SUB AX,BPB_RES ;don't count boot sector(s)
- SUB AX,DIR_SECTORS ;don't count directory sectors
- JG VAL_FAT_A ;jump if some remaining
- MOV BPB_SSZ,DFLT_SSZ ;force default sector size
- OR ERR_FLAG,ERR_SSZ+ERR_PASS ;indicate sector size adjusted
- JMP SHORT VAL_FAT_X ;recompute all values
- VAL_FAT_A:
- XOR DX,DX ;clear DX for division
- MOV CL,BPB_AUSZ ;CX = sectors/cluster
- XOR CH,CH
- DIV CX ;whole number of clusters in AX
- ADD DX,0FFFFH ;set carry if remainder
- ADC AX,0 ;increment AX if remainder
- CMP AX,MAX_FATE ;number of FAT entries too large?
- JBE VAL_FAT_C ;no, continue
-
- MOV AX,BPB_SSZ ;pick up current sector size
- CMP AX,VAL_SSZ_L ;already at largest permitted?
- JE VAL_FAT_B ;yes, can't make it any larger
-
- SHL BPB_SSZ,1 ;double sector size
- OR ERR_FLAG,ERR_SSZB ;indicate sector size adjusted
- JMP SHORT VAL_FAT_X ;recompute all sizes with new BPBSSZ
-
- VAL_FAT_B: ;sector size is at maximum
- SHL BPB_AUSZ,1 ;double allocation unit size
- OR ERR_FLAG,ERR_PASS ;indicate another pass required
- JMP SHORT VAL_FAT_X ;recompute values
-
- VAL_FAT_C: ;FAT size = 1.5 * number of clusters
- MOV CX,AX ;number of clusters
- SHL AX,1 ;* 2
- ADD AX,CX ;* 3
- SHR AX,1 ;* 1.5
-
- ADC AX,3 ;add 3 bytes for first 2 FAT entries
- ;(media descriptor and FFFFH), and CY
- XOR DX,DX ;clear DX for division
- DIV BPB_SSZ ;FAT size/sector size
- ADD DX,0FFFFH ;set carry if remainder
- ADC AX,0 ;round upward
- MOV BPB_FATSZ,AX ;number of sectors for 1 FAT copy
- VAL_FAT_X:
- RET
- VAL_FAT ENDP
-
-
- VALIDATE ENDP
-
- SUBTTL COPY_BPB Copy BPB to Boot Record
- PAGE
- ;-----------------------------------------------------------------------;
- ; COPY_BPB copies the BIOS Parameter Block (BPB) ;
- ; to the VDISK Boot Record ;
- ;-----------------------------------------------------------------------;
- ASSUME DS:CSEG
- COPY_BPB PROC ;Copy BBP to Boot Record
- PUSH DS
- POP ES ;set ES = DS
-
- MOV CX,BPB_LEN ;length of BPB
- MOV SI,OFFSET BPB ;source offset
- MOV DI,OFFSET BOOT_BPB ;target offset
- REP MOVSB ;copy BPB to boot record
- RET
- COPY_BPB ENDP
-
- SUBTTL VERIFY_EXTENDER
- PAGE
- ;-----------------------------------------------------------------------;
- ; VERIFY_EXTENDER makes sure that if an Expansion Unit is ;
- ; installed, the memory size switches on the Extender Card ;
- ; are correctly set. ;
- ;-----------------------------------------------------------------------;
-
- ASSUME DS:CSEG
- EXT_P210 EQU 0210H ;write to latch expansion bus data
- ;read to verify expansion bus data
- EXT_P213 EQU 0213H ;Expansion Unit status
-
- VERIFY_EXTENDER PROC
-
- NOP
-
- MOV DX,EXT_P210 ;Expansion bus data port address
-
- MOV AX,5555H ;set data pattern
- OUT DX,AL ;write 55H to control port
- PUSH DX ;load data line
- POP DX ;load data line
- IN AL,DX ;recover data
- CMP AH,AL ;did we recover the same data?
- JNE VERIFY_EXTENDER_X ;if not, no extender card
-
- NOT AX ;set AX = 0AAAAH
- OUT DX,AL ;write 0AAH to control port
- PUSH DX ;load data line
- POP DX ;load data line
- IN AL,DX ;recover data
- CMP AH,AL ;did we recover the same data?
- JNE VERIFY_EXTENDER_X ;if not, no extender card
-
- ;Expansion Unit is present.
-
- ;Determine what the switch settings should be on the Extender Card
-
- INT MEM_SIZE ;get system memory size in KB in AX
- ADD AX,63D ;memory size + 63K
- MOV CL,6 ;2^6 = 64
- SHR AX,CL ;divide by 64
- ;AX is highest segment address
- MOV AH,AL ;save number of segments
-
- ;Read Expander card switch settings
-
- MOV DX,EXT_P213 ;expansion unit status
- IN AL,DX ;read status
- ;bits 7-4 (hi nibble) are switches
- MOV CL,4 ;shift count
- SHR AL,CL ;shift switches to bits 3-0 of AL
-
- CMP AH,AL ;do switches match memory size?
- JE VERIFY_EXTENDER_X ;yes, exit normally
-
- OR ERR_FLAG,ERR_EXTSW ;indicate switch settings are wrong
-
- VERIFY_EXTENDER_X:
- RET
- VERIFY_EXTENDER ENDP
-
- SUBTTL UPDATE_AVAIL
- PAGE
- ;-----------------------------------------------------------------------;
- ; UPDATE_AVAIL updates the address of the first byte in extended ;
- ; memory not used by any VDISK buffer ;
- ;-----------------------------------------------------------------------;
- UPDATE_AVAIL PROC ;update AVAIL_LO and AVAIL_HI of first VDISK
- MOV AX,BUFF_SIZE ;number of KB of VDISK buffer
- MUL C1024 ;DX,AX = number of bytes of VDISK buffer
-
- PUSH DS
- MOV DS,FIRST_VDISK ;set DS to first VDISK
- ADD DS:AVAIL_LO,AX ;update first available byte location
- ADC DS:AVAIL_HI,DL
- POP DS
- RET
- UPDATE_AVAIL ENDP
-
- SUBTTL FORMAT_VDISK
- PAGE
- ;-----------------------------------------------------------------------;
- ; This Request Header is used by MOVE_VDISK to move the ;
- ; first few sectors of the virtual disk (boot, FAT, and ;
- ; Directory) into extended memory. ;
- ;-----------------------------------------------------------------------;
-
- MOVE_RH DB MOVE_RH_L ;length of request header
- DB 0 ;sub unit
- DB 8 ;output operation
- DW 0 ;status
- DQ ? ;reserved for DOS
- DB ? ;media descriptor byte
- MOVE_RHO DW ? ;offset of data transfer address
- MOVE_RHS DW ? ;segment of data transfer address
- MOVE_RHCNT DW ? ;count of sectors to transfer
- DW 0 ;starting sector number
- MOVE_RH_L EQU $-MOVE_RH ;length of request header
-
- ;-----------------------------------------------------------------------;
- ; FORMAT_VDISK formats the boot sector, FAT, and directory of an ;
- ; extended memory VDISK in storage immediately following ;
- ; VDISK code, in preparation for moving to extended memory. ;
- ;-----------------------------------------------------------------------;
- FORMAT_VDISK PROC ;format boot record, FATs and directory
-
- MOV AX,CS ;compute 20-bit address
- MUL WPARA_SIZE ;16 * segment
- ADD AX,OFFSET MSGEND ;+ offset
- ADC DL,0 ;pick up carry
- ADD AX,STACK_SIZE ;plus stack size
- ADC DL,0 ;pick up carry
-
- DIV WPARA_SIZE ;split into segment(AX)&offset(DX)
- MOV MOVE_RHS,AX ;save in Request Header for move
- MOV MOVE_RHO,DX
-
- MOV DI,DX ;offset to DI
- MOV ES,AX ;segment to ES
-
- ;copy the boot record
-
- MOV SI,OFFSET BOOT_RECORD ;point to source field
- MOV AX,BPB_RES ;number of reserved sectors
- MUL BPB_SSZ ;* sector size = length of boot records
- MOV CX,AX ;length to CX for move
- REP MOVSB ;move boot record(s)
-
- ;format the FAT(s)
-
- MOV CL,BPB_FATN ;number of FATs
- XOR CH,CH
- FORMAT_VDISK_A: ;set up one FAT
-
- PUSH CX ;save loop counter on stack
- MOV AL,BPB_MCB ;media control byte
- STOSB ;store media control byte, increment DI
- MOV AX,0FFFFH ;bytes 2 and 3 of FAT are 0FFH
- STOSW
- MOV AX,BPB_FATSZ ;number of sectors per FAT
- MUL BPB_SSZ ;* sector size = length of FAT in bytes
- SUB AX,3 ;less the 3 bytes we've stored
- MOV CX,AX ;count to CX
- XOR AX,AX
- REP STOSB ;clear remainder of FAT
- POP CX ;get loop counter off stack
- LOOP FORMAT_VDISK_A ;loop for all copies of the FAT
-
- ;Format the directory
-
- MOV SI,OFFSET VOL_LABEL ;point to volume label
- MOV CX,VOL_LABEL_LEN ;length of volume directory entry
- REP MOVSB ;move volume id to directory
- MOV AX,DIR_ENTRY_SIZE ;length of 1 directory entry
- MUL BPB_DIRN ;* number entries = bytes of directory
- SUB AX,VOL_LABEL_LEN ;less length of volume label
- MOV CX,AX ;CX = length of rest of directory
- XOR AX,AX
- REP STOSB ;clear directory to nulls
- RET
- FORMAT_VDISK ENDP
-
- SUBTTL MOVE_VDISK
- PAGE
- ;-----------------------------------------------------------------------;
- ; MOVE_VDISK moves the formatted boot sector, FAT, and directory ;
- ; into extended memory. ;
- ;-----------------------------------------------------------------------;
-
- MOVE_VDISK PROC
- MOV AL,BPB_FATN ;number of FAT copies
- CBW ;clear AH
- MUL BPB_FATSZ ;number of FAT sectors
- ADD AX,BPB_RES ;+ reserved sectors
- ADD AX,DIR_SECTORS ;+ directory sectors
- MOV MOVE_RHCNT,AX ;store as I/O length
-
- MOV BX,OFFSET MOVE_RH ;DS:BX point to request header
- PUSH DS ;make sure DS gets preserved
- CALL INOUT ;move to extended memory
- POP DS
- RET
- MOVE_VDISK ENDP
-
- SUBTTL UPDATE_BOOT
- PAGE
- ;-----------------------------------------------------------------------;
- ; UPDATE_BOOT updates the BOOT_EM word in the first extended ;
- ; memory VDISK (address 10 001EH) to show the kilobyte address ;
- ; of the first extended memory byte not used by any VDISK buffer. ;
- ;-----------------------------------------------------------------------;
- UPDATE_BOOT PROC
- PUSH DS
- MOV DS,FIRST_VDISK ;set DS to first VDISK
- MOV AX,DS:AVAIL_LO ;24-bit end address of all VDISKs
- MOV DL,DS:AVAIL_HI
- XOR DH,DH
- POP DS
- DIV C1024 ;address / 1024
- MOV BOOT_EM,AX ;store in temporary location
-
- MOV AX,2 ;length of block move is 2 bytes
- MOV TGT.DESC_LMT,AX
- MOV SRC.DESC_LMT,AX
-
- MOV AX,PARA_SIZE ;16
- MOV CX,CS ;our segment address
- MUL CX ;16 * segment address
- ADD AX,OFFSET BOOT_EM ;+ offset of source data
- ADC DL,0 ;pick up any carry
-
- MOV SRC.DESC_BASEL,AX ;store source base address
- MOV SRC.DESC_BASEH,DL
-
- MOV TGT.DESC_BASEL,BOOT_EM_OFF ;offset of BOOT_EM
- MOV TGT.DESC_BASEH,10H ;1 megabyte
-
- MOV CX,1 ;move 1 word
-
- PUSH CS
- POP ES
- MOV SI,OFFSET GDT ;ES:DI point to global descriptor table
-
- MOV AH,EM_BLKMOVE ;function code
- INT EM_INT ;move BOOT_EM to 10 001EH
- RET
- UPDATE_BOOT ENDP
-
- SUBTTL STEAL_INT19
- PAGE
- ;-----------------------------------------------------------------------;
- ; STEAL_INT19 changes the INT 19H vector to point to this VDISK ;
- ; so that subsequent extended memory VDISKS may locate the ;
- ; AVAIL_HI and AVAIL_LO fields to determine their buffer start ;
- ; addresses. ;
- ;-----------------------------------------------------------------------;
- STEAL_INT19 PROC
- PUSH DS
- XOR AX,AX
- MOV DS,AX ;set DS = 0
- ASSUME DS:INT_VEC
- CLI ;disable interrupts
- LES DI,DS:BOOT_VEC ;get original vector's content
- MOV CS:INTV19O,DI ;save original vector
- MOV CS:INTV19S,ES
- MOV DS:BOOT_VECO,OFFSET VDISK_INT19 ;offset of new INT routine
- MOV DS:BOOT_VECS,CS ;segment of new INT routine
- STI ;enable interrupts again
- POP DS ;restore DS
- RET
- STEAL_INT19 ENDP
-
- SUBTTL FILL_RH Fill in Request Header
- PAGE
- ;-----------------------------------------------------------------------;
- ; FILL_RH fills in the Request Header returned to DOS ;
- ;-----------------------------------------------------------------------;
- ASSUME DS:CSEG
- FILL_RH PROC ;fill in INIT Request Header fields
- MOV CX,START_BUFFER_PARA ;segment end of VDISK resident code
- MOV AX,PARAS_PER_SECTOR ;paragraphs per sector
- MUL BPB_SECN ;* number of sectors
- ADD AX,CX ;+ starting segment
- MOV DX,AX ;DX is segment of end VDISK buffer
- CMP EM_SW,0 ;if extended memory not requested
- JE FILL_RH_A ;skip DX adjustment
-
- MOV DX,CX ;end of code segment addr
- FILL_RH_A: ;DX is proper ending segment address
- MOV AL,1 ;number of units
- TEST ERR_FLAG,ERR_SYSSZ+ERR_EXTSW ;if bypassing install
- JZ FILL_RH_B ;jump if installing driver
-
- MOV DX,CS ;segment of end address
- XOR AL,AL ;number of units is zero
- FILL_RH_B:
- PUSH DS ;preserve DS
- LDS BX,RH_PTRA ;get Request Header addr in DS:BX
- MOV RH.RH0_NUN,AL ;store number of units (0 or 1)
- MOV RH.RH0_ENDO,0 ;end offset is always zero
- MOV RH.RH0_ENDS,DX ;end of VDISK or end of buffer
- MOV RH.RH0_BPBO,OFFSET BPB_PTR
- MOV RH.RH0_BPBS,CS ;BPB array address
- POP DS ;restore DS
- RET
- FILL_RH ENDP
-
- SUBTTL WRITE_MESSAGES and associated routines
- PAGE
- ;-----------------------------------------------------------------------;
- ; WRITE_MESSAGE writes a series of messages to the standard ;
- ; output device showing the VDISK parameter values actually used. ;
- ;-----------------------------------------------------------------------;
-
- ;These external references are resolved by messages in VDISKMSG
- ;Messages placed in separate assembly to ease translation effort.
- ;Each message string is terminated with a '$'
-
- EXTRN IMSG:BYTE ;VDISK installing virtual disk
- EXTRN ERRM1:BYTE ; Buffer size adjusted CR LF
- EXTRN ERRM2:BYTE ; Sector size adjusted CR LF
- EXTRN ERRM3:BYTE ; Directory entries adjusted CR LF
- EXTRN ERRM4:BYTE ;VDISK not installed - insufficient memory CR LF
- EXTRN ERRM5:BYTE ; Invalid switch character CR LF
- EXTRN ERRM6:BYTE ;VDISK not installed - Extender card switches
- ; do not match system memory size CR LF
- EXTRN MSG1:BYTE ; Buffer size:
- EXTRN MSG2:BYTE ; KB CR LF
- EXTRN MSG3:BYTE ; Sector size:
- EXTRN MSG4:BYTE ; Directory entries:
- EXTRN MSGCRLF:BYTE ;CR LF
- EXTRN MSGEND:BYTE ;last byte of VDISKMSG
-
- CHAR4 DB 'nnnn$' ;build 4 ASCII decimal digits
-
- ASSUME DS:CSEG
- WRITE_MESSAGES PROC ;display all messages
-
- MSG IMSG ;'VDISK Version 1.0 virtual disk $'
-
- ;If DOS Version 3 is in use, the Request Header contains a drive code
- ;that is displayed to show which drive letter was assigned to this
- ;VDISK. This field is not present in the DOS Version 2 Request Header.
-
- MOV AH,DOS_VERS ;get DOS version call
- INT DOS ;invoke DOS
-
- CMP AL,3 ;DOS Version 3 or greater?
- JB WRITE_MESSAGES_A ;no, bypass drive letter
-
- PUSH DS ;preserve DS
- LDS BX,RH_PTRA ;get Request Header Address
- MOV DL,RH.RH0_DRIV ;get drive code
- ADD DL,'A' ;convert to drive letter
- POP DS ;restore DS
-
- MOV AH,DOS_PCHR ;function code to write character in DL
- INT DOS ;display drive letter
-
- MOV DL,':' ;display trailing colon
- INT DOS
-
- WRITE_MESSAGES_A:
- MSG MSGCRLF ;end the first line
-
- ;If any of the user specified values has been adjusted, issue an
- ;appropriate message
-
- TEST ERR_FLAG,ERR_BSIZE ;was buffersize adjusted?
- JZ WRITE_MESSAGES_B ;if not, skip message
-
- MSG ERRM1 ;buffer size adjusted
-
- WRITE_MESSAGES_B:
- TEST ERR_FLAG,ERR_SSZ ;was sector size adjusted?
- JZ WRITE_MESSAGES_C ;if not, skip message
-
- MSG ERRM2 ;sector size adjusted
-
- WRITE_MESSAGES_C:
- TEST ERR_FLAG,ERR_DIRN ;were directory entries adjusted?
- JZ WRITE_MESSAGES_D ;if not, skip message
-
- MSG ERRM3 ;directory entries adjusted
-
- WRITE_MESSAGES_D:
- TEST ERR_FLAG,ERR_SWTCH ;was an invalid switch character found?
- JZ WRITE_MESSAGES_E ;if not, skip message
-
- MSG ERRM5 ;invalid switch character
-
- WRITE_MESSAGES_E:
- TEST ERR_FLAG,ERR_SYSSZ ;is system size too small to install?
- JZ WRITE_MESSAGES_F ;if not, bypass error message
-
- MSG ERRM4 ;too large for system storage
- RET ;skip messages showing adjusted sizes
-
- WRITE_MESSAGES_F:
- TEST ERR_FLAG,ERR_EXTSW ;extender card switches wrong?
- JZ WRITE_MESSAGES_G ;if not, bypass error message
-
- MSG ERRM6 ;extender card switches wrong msg
- RET ;skip remaining messages
-
- WRITE_MESSAGES_G: ;display adjusted size messages
- MSG MSG1 ;buffer size:
-
- MOV DX,BUFF_SIZE ;buffer size in binary
- CALL STOR_SIZE ;convert binary to ASCII decimal
- MSG CHAR4 ;print 4 decimals
- MSG MSG2 ;KB,CR,LF
-
- MSG MSG3 ;sector size:
- MOV DX,BPB_SSZ
- CALL STOR_SIZE ;convert binary to ASCII decimal
- MSG CHAR4 ;print 4 decimals
- MSG MSGCRLF ;finish off line
-
- MSG MSG4 ;directory entries:
- MOV DX,BPB_DIRN ;number of directory entries
- CALL STOR_SIZE
- MSG CHAR4 ;print 4 decimals
- MSG MSGCRLF ;finish off the line
- MSG MSGCRLF ;one more blank line to set it off
- RET ;return to INIT_P1
-
- ;SHOW_MSG displays a string at DS:DX on the standard output device
- ;String is terminated by a $
-
- SHOW_MSG PROC ;display string at DS:DX
- PUSH AX ;preserve AX across call
- MOV AH,DOS_PSTR ;DOS function code
- INT DOS ;invoke DOS print string function
- POP AX ;restore AX
- RET
- SHOW_MSG ENDP
-
- ;STOR_SIZE converts the content of DX to 4 decimal characters in CHAR4
- ;(DX must be <= 9999)
-
- STOR_SIZE PROC ;convert DX to 4 decimals in CHAR4
- ;develop 4 packed decimal digits in AX
- XOR AX,AX ;clear result register
- MOV CX,16 ;shift count
- STOR_SIZE_B:
- SHL DX,1 ;shift high bit into carry
- ADC AL,AL ;double AL, carry in
- DAA ;adjust for packed decimal
- XCHG AL,AH
- ADC AL,AL ;double high byte, carry in
- DAA
- XCHG AL,AH
- LOOP STOR_SIZE_B ;AX contains 4 packed decimal digits
-
- PUSH CS
- POP ES ;point ES:DI to output string
- MOV DI,OFFSET CHAR4
-
- MOV CX,1310H ;10H in CL is difference between blank and zero
- ;13H in CH is decremented and ANDed to force
- ;last character not to be zero suppressed
- PUSH AX ;save AX on stack
- MOV DL,AH ;2 decimals to DL
- CALL STOR_SIZE_2 ;display DL as 2 decimal characters
- POP DX ;bring low 2 decimals into DL
- STOR_SIZE_2: ;display DL as 2 decimal characters
- MOV DH,DL ;save 2 decimals in DH
- SHR DL,1 ;shift high order decimal right to low position
- SHR DL,1
- SHR DL,1
- SHR DL,1
- CALL STOR_SIZE_1 ;display low nibble of DL
- MOV DL,DH ;get low decimal from pair
- STOR_SIZE_1: ;display low nibble of DL as 1 decimal char
- AND DL,0FH ;clear high nibble
- JZ STOR_SIZE_Z ;if digit is significant,
- XOR CL,CL ;defeat zero suppression
- STOR_SIZE_Z:
- DEC CH ;decrement zero suppress counter
- AND CL,CH ;always display least significant digit
- OR DL,'0' ;convert packed decimal to ASCII
- SUB DL,CL ;zero suppress (nop or change '0' to ' ')
- MOV AL,DL ;char to DL
- STOSB ;store char at ES:DI, increment DI
- RET
- STOR_SIZE ENDP
-
- WRITE_MESSAGES ENDP
-
- INIT_P1 ENDP ;end of INIT part one
-
- ;VDISKMSG is linked beyond this module.
-
- CSEG ENDS
- END